/**
 * @file    inf_74hc595.c
 * @author  yhy
 * @brief   74HC595移位寄存器源文件
 * @version 1.01
 * @date    2025-07-19
 *
 * @copyright Copyright (c) 2025
 *
 * @details
 * Change Logs:
 * Date           Author       Notes
 * 2025-07-19     yhy          the first version V1.00
 * 2025-11-06     yhy          修复了所有通道共享duty_cycle的问题   V1.01
 *
 */
#include "inf_74hc595.h"

#include "common_debug.h"
#include "drv_spi.h"

#include <stdio.h>
#include <string.h>

#define SR_74HC595_DATA_MAXSIZE 12

static void inf_74hc595_send_data(void);

static uint32_t shift_reg_data[SR_74HC595_DATA_MAXSIZE]                       = { 0 }; /* 74HC595数据缓存 */
static uint8_t  shift_reg_data_u8[SR_74HC595_DATA_MAXSIZE * sizeof(uint32_t)] = {
    0
}; /* 74HC595数据缓存, 用于占空比输出数据 */
static uint8_t channel_duty_steps[SR_74HC595_CHANNEL_MAX] = {
    0
}; /* 每个通道的占空比步进(0~SR_74HC595_DATA_MAXSIZE) */
static uint32_t output_state = 0; /* 当前通道使能状态位掩码 */

/**
 * @brief 初始化74HC595移位寄存器
 *
 * @return result_e 初始化结果, 初始化成功返回RESULT_STATUS_OK, 初始化失败返回其他错误码
 */
result_e inf_74hc595_init(void)
{
    snf_spi_config_t spi_config = {
        .instance       = SPI_INSTANCE_SPI0_0,
        .data_size      = SPI_DATA_SIZE_32BIT,
        .spi_callback   = NULL,
        .callback_param = NULL,
    };

    return snf_drv_spi_init(&spi_config);
}

/**
 * @brief 设置74HC595通道状态
 *
 * @param channel   通道号
 * @param state     状态
 * @return result_e 设置结果, 设置成功返回RESULT_STATUS_OK, 设置失败返回其他错误码
 */
result_e inf_74hc595_set_channel(sr_74hc595_channel_e channel, sr_74hc595_state_e state)
{
    if (channel >= SR_74HC595_CHANNEL_MAX || state >= SR_74HC595_STATE_MAX) {
        return RESULT_STATUS_INVALID_PARAM;
    }

    uint8_t bit_pos = (uint8_t)(channel);

    if (state == SR_74HC595_STATE_ENABLE) {
        output_state |= (1u << bit_pos);
    }
    else {
        output_state &= ~(1u << bit_pos);
    }

    inf_74hc595_send_data();

    return RESULT_STATUS_OK;
}

/**
 * @brief 设置74HC595通道占空比
 *
 * @param channel   通道号
 * @param duty      占空比, 0~100
 * @return result_e 设置结果, 设置成功返回RESULT_STATUS_OK, 设置失败返回其他错误码
 */
result_e inf_74hc595_set_duty(sr_74hc595_channel_e channel, int8_t duty)
{
    if (channel >= SR_74HC595_CHANNEL_MAX || duty < 0 || duty > 100) {
        return RESULT_STATUS_INVALID_PARAM;
    }

    uint8_t steps               = (uint8_t)((duty * SR_74HC595_DATA_MAXSIZE) / 100);
    channel_duty_steps[channel] = steps;

    if (steps)
        inf_74hc595_set_channel(channel, SR_74HC595_STATE_ENABLE);
    else
        inf_74hc595_set_channel(channel, SR_74HC595_STATE_DISABLE);

    return RESULT_STATUS_OK;
}

/**
 * @brief 发送74HC595数据
 *
 * @param output_data 74HC595输出数据
 * @param duty_cycle  74HC595占空比, 0~100
 */
static void inf_74hc595_send_data(void)
{
    /* 根据每个通道的占空比生成每个时隙的输出数据 */
    for (uint8_t i = 0; i < SR_74HC595_DATA_MAXSIZE; ++i) {
        uint32_t slice_data = 0;
        for (uint8_t ch = 0; ch < SR_74HC595_CHANNEL_MAX; ++ch) {
            if ((output_state & (1u << ch)) && (i < channel_duty_steps[ch])) {
                slice_data |= (1u << ch);
            }
        }
        shift_reg_data[i] = slice_data;
    }

    /* 将u32数据转换成u8数据 */
    memcpy(shift_reg_data_u8, shift_reg_data, sizeof(shift_reg_data));

    /* 发送数据 */
    result_e result = snf_drv_spi_transfer(SPI_INSTANCE_SPI0_0, shift_reg_data_u8, NULL,
                                           SR_74HC595_DATA_MAXSIZE * sizeof(uint32_t));
}
